//此hpp用于形成  单生产者消费者模型 中的交易区域，这里使用阻塞队列来完成
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "lockProtect.hpp"
//最大容量
#define MAX_CAPACITY 5
//使用模版，让资源可以是任意类型，包括class/strcut类、函数等
template <class T>
class QueueBlock
{
public:
    ////////////////////////////////////////////////////////////
    // 这里设计成员有mutex、cond的目的是，让外部不必担心线程安全的问题 //
    // 所以构造函数和析构函数这里就要自动初始化和销毁mutex、cond      //
    ////////////////////////////////////////////////////////////

    //构造函数
    QueueBlock(int capacity = MAX_CAPACITY)
        : _capacity(capacity)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
    }

    //析构函数
    ~QueueBlock()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
    }

    //生产资源，已经涉及到共享资源的访问，所以要加锁解锁
    void Push(T& data)
    {
        ProtectResourse protect(&_mutex);
        // pthread_mutex_lock(&_mutex);
        {
            // if(IsFull())
            while(IsFull()) //这里使用while，是怕一次唤醒多个线程，有伪唤醒，导致满了还生产
            {
                pthread_cond_wait(&_p_cond, &_mutex);
            }

            _q.push(data);
            pthread_cond_signal(&_c_cond);
        }
        // pthread_mutex_unlock(&_mutex);
    }

    //消费资源，也会涉及到共享资源的访问，所以也要加锁解锁
    void Pop(T* data)
    {
        ProtectResourse protect(&_mutex);
        // pthread_mutex_lock(&_mutex);
        {
            // if(IsEmpty())
            while(IsEmpty()) //这里使用while，是因为一次唤醒多个线程，有伪唤醒，导致没有resourse还访问
            {
                pthread_cond_wait(&_c_cond, &_mutex);
            }

            *data = _q.front();
            _q.pop();
            pthread_cond_signal(&_p_cond);
        }
        // pthread_mutex_unlock(&_mutex);

    }

    //判断资源是否已经满了
    bool IsFull()
    {
        return _q.size() == _capacity;
    }

    //判断是否资源为空
    bool IsEmpty()
    {
        return _q.size() == 0;
    }
    
private:
    std::queue<T> _q;             //阻塞队列
    int _capacity;           //队列的最大容量  
    pthread_mutex_t _mutex;   //互斥锁
    pthread_cond_t _p_cond;  //给procductor的条件变量，让consumer控制
    pthread_cond_t _c_cond;  //给consumer的条件变量，让productor控制
};